package com.nepu.spark.realtime.util

import java.lang.reflect.{Field, Method, Modifier}

import com.nepu.spark.realtime.bean.{DauInfo, PageLog}

import scala.util.control.Breaks

/**
  * 本类的作用是利用反射进行bean的copy
  *
  * @author chenshuaijun
  * @create 2022-11-01 11:32
  */
object MyBeanCopyUtils {

  def fieldCopy(srcObj: AnyRef, destObj: AnyRef): Unit = {
    // 首先进行安全性的效验
    if (srcObj == null || destObj == null) {
      return
    }
    // 转换成class对象
    val srcClass: Class[_ <: AnyRef] = srcObj.getClass
    val destClass: Class[_ <: AnyRef] = destObj.getClass
    // 获取srcObj对象中的所有的属性
    val srcFields: Array[Field] = srcClass.getDeclaredFields
    // 遍历对应的属性数组
    for (field <- srcFields) {
      // 解决srcObj中有属性，而dest中没有属性而产生的异常
      Breaks.breakable {
        // 因为我们获取属性的值，或者是更改属性的值，是需要使用到get和set方法处理的，所以这里先进行get和set方法名的封装
        // 在scala中一个属性对应的get方法就是属性名本身：fieldName()
        // 在scala中一个属性对应的set方法就是: fieldName_$eq(参数类型)
        val getName: String = field.getName
        val setName: String = field.getName + "_$eq"
        // 获取srcObj的get对象的方法
        val getMethod: Method = srcClass.getDeclaredMethod(getName)
        // 获取destObj的set方法的对象
        val setMethod: Method =
          try {
            // 这里需要try一下的原因是因为srcObj中有的属性，destObj中不一定有
            destClass.getDeclaredMethod(setName, field.getType)
          } catch {
            // 直接跳出循环
            case e: Exception => Breaks.break()
          }
        // 判断destObj对应的属性是否允许修改
        val destField: Field = destClass.getDeclaredField(field.getName)
        val isModifiers: Int = destField.getModifiers
        if (isModifiers.equals(Modifier.FINAL)) {
          Breaks.break()
        }
        setMethod.invoke(destObj, getMethod.invoke(srcObj))
      }
    }
  }

  def main(args: Array[String]): Unit = {
    val dauInfo = new DauInfo()
    val pageLog = PageLog("123", "1", "maxOS", "web", "yes", "m", "mid123", null, null, 0L, null, null, 0L, null, null, null)
    println(dauInfo)
    fieldCopy(pageLog, dauInfo)
    println(dauInfo)
  }
}
